home *** CD-ROM | disk | FTP | other *** search
/ Windows Game Programming for Dummies (2nd Edition) / WinGamProgFD.iso / pc / DirectX SDK / DXSDK / samples / Multimedia / DirectShow / Players / DDrawXCL / ddrawobj.cpp next >
Encoding:
C/C++ Source or Header  |  2001-10-08  |  22.2 KB  |  675 lines

  1. //------------------------------------------------------------------------------
  2. // File: DDrawObj.cpp
  3. //
  4. // Desc: DirectShow sample code - implementation of DDrawObject class.
  5. //
  6. // Copyright (c) 1993-2001 Microsoft Corporation.  All rights reserved.
  7. //------------------------------------------------------------------------------
  8.  
  9.  
  10. #include <streams.h>
  11. #include <windows.h>
  12.  
  13. #include "DDrawObj.h"
  14. #include "VidPlay.h"
  15.  
  16.  
  17. //
  18. // CDDrawObject constructor
  19. //
  20. CDDrawObject::CDDrawObject(HWND hWndApp)
  21. {
  22.     DbgLog((LOG_TRACE, 3, TEXT("CDDrawObject c-tor entered"))) ;
  23.     
  24.     m_pDDObject = NULL ;
  25.     m_pPrimary = NULL ;
  26.     m_pBackBuff = NULL ;
  27.     
  28.     // Default colors to be used for filling
  29.     m_dwScrnColor = RGB(0, 0, 0) ;
  30.     m_dwVideoKeyColor = RGB(255, 0, 255) ;
  31.     
  32.     // Rects for the screen area and video area
  33.     SetRect(&m_RectScrn, 0, 0, 0, 0) ;
  34.     SetRect(&m_RectVideo, 0, 0, 0, 0) ;
  35.     
  36.     // some flags, count, messages for buffer flipping
  37.     m_bInExclMode = FALSE ;
  38.     m_iCount = 0 ;
  39.     m_bFrontBuff = TRUE ;
  40.     m_szFrontMsg = TEXT("Front Buffer" );
  41.     m_szBackMsg  = TEXT("Back Buffer" );
  42.     m_szDirection = TEXT("Press the 'Arrow' keys to move the ball. Hit 'Esc' to stop playback." );
  43.     
  44.     // Create brush and pen for drawing the filled ball
  45.     LOGBRUSH  lb ;
  46.     lb.lbStyle = BS_HATCHED ;
  47.     lb.lbColor = RGB(0, 255, 0) ;
  48.     lb.lbHatch = HS_CROSS ;
  49.     m_hBrush = CreateBrushIndirect(&lb) ;
  50.     ASSERT(NULL != m_hBrush) ;
  51.     
  52.     m_hPen = CreatePen(PS_SOLID, 2, RGB(0, 0, 255)) ;
  53.     ASSERT(NULL != m_hPen) ;
  54.  
  55.     HRESULT  hr=S_OK ;
  56.     m_pOverlayCallback = (IDDrawExclModeVideoCallback *) new COverlayCallback(this, hWndApp, &hr) ;
  57.     ASSERT(SUCCEEDED(hr)) ;
  58.     m_bOverlayVisible = FALSE ;  // don't draw color key until it's OK-ed by OverlayMixer
  59. }
  60.  
  61.  
  62. //
  63. // CDDrawObject destructor
  64. //
  65. CDDrawObject::~CDDrawObject(void)
  66. {
  67.     DbgLog((LOG_TRACE, 3, TEXT("CDDrawObject d-tor entered"))) ;
  68.  
  69.     // Let go of the overlay notification callback object now
  70.     if (m_pOverlayCallback)
  71.         m_pOverlayCallback->Release() ;  // done with callback object now
  72.  
  73.     // delete the pen and brush we created for drawing the ball
  74.     if (m_hPen)
  75.         DeleteObject(m_hPen) ;
  76.     if (m_hBrush)
  77.         DeleteObject(m_hBrush) ;
  78.     
  79.     if (m_pBackBuff)
  80.         m_pBackBuff->Release() ;
  81.     if (m_pPrimary)
  82.         m_pPrimary->Release() ;
  83.     
  84.     if (m_pDDObject)
  85.         m_pDDObject->Release() ;
  86.     
  87.     DbgLog((LOG_TRACE, 3, TEXT("CDDrawObject d-tor exiting..."))) ;
  88. }
  89.  
  90.  
  91. //
  92. // CDDrawObject::Initialize(): Just creates a DDraw object.
  93. //
  94. BOOL CDDrawObject::Initialize(HWND hWndApp)
  95. {
  96.     DbgLog((LOG_TRACE, 5, TEXT("CDDrawObject::Initialize() entered"))) ;
  97.     
  98.     HRESULT hr = DirectDrawCreate(NULL, &m_pDDObject, NULL) ;
  99.     if (FAILED(hr) || NULL == m_pDDObject)
  100.     {
  101.         MessageBox(hWndApp, 
  102.             TEXT("Can't create a DirectDraw object.\nPress OK to end the app."), 
  103.             TEXT("Error"), MB_OK | MB_ICONSTOP) ;
  104.         return FALSE ;
  105.     }
  106.     
  107.     return TRUE;
  108. }
  109.  
  110.  
  111. #define SCRN_WIDTH    800
  112. #define SCRN_HEIGHT   600
  113. #define SCRN_BITDEPTH   8
  114.  
  115. //
  116. // CDDrawObject::StartExclusiveMode(): Gets into fullscreen exclusive mode, sets
  117. // display mode to 800x600x8, creates a flipping primary surface with one back 
  118. // buffer, gets the surface size and inits some variables.
  119. //
  120. // NOTE: Please don't bother about the "#ifndef NOFLIP"s.  They were there
  121. // for testing.
  122. //
  123. HRESULT CDDrawObject::StartExclusiveMode(HWND hWndApp)
  124. {
  125.     DbgLog((LOG_TRACE, 5, TEXT("CDDrawObject::StartExclusiveMode() entered"))) ;
  126.     
  127.     HRESULT         hr ;
  128.     DDSURFACEDESC   ddsd ;
  129.     DDSCAPS         ddscaps ;
  130.     
  131.     if (! Initialize(hWndApp) )
  132.         return E_FAIL ;
  133.  
  134.     // Get into fullscreen exclusive mode
  135. #ifndef NOFLIP
  136.     hr = m_pDDObject->SetCooperativeLevel(hWndApp,
  137.         DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN | DDSCL_ALLOWREBOOT) ;
  138.     if (FAILED(hr))
  139.     {
  140.         MessageBox(hWndApp, 
  141.             TEXT("SetCooperativeLevel() failed to go into exclusive mode"), 
  142.             TEXT("Error"), MB_OK | MB_ICONSTOP) ;
  143.         return hr ;
  144.     }
  145. #else
  146.     hr = m_pDDObject->SetCooperativeLevel(hWndApp, DDSCL_NORMAL) ;
  147.     if (FAILED(hr))
  148.     {
  149.         MessageBox(hWndApp, 
  150.             TEXT("SetCooperativeLevel() failed to go into normal mode"), 
  151.             TEXT("Error"), MB_OK | MB_ICONSTOP) ;
  152.         return hr ;
  153.     }
  154. #endif // NOFLIP
  155.     
  156. #ifndef NOFLIP
  157.     hr = m_pDDObject->SetDisplayMode(SCRN_WIDTH, SCRN_HEIGHT, SCRN_BITDEPTH) ;
  158.     if (FAILED(hr))
  159.     {
  160.         DbgLog((LOG_ERROR, 0, TEXT("ERROR: SetDisplayMode failed (Error 0x%lx)"), hr)) ;
  161.         MessageBox(hWndApp, TEXT("SetDisplayMode(640, 480, 8) failed"), 
  162.             TEXT("Error"), MB_OK | MB_ICONSTOP) ;
  163.         return hr ;
  164.     }
  165. #endif // NOFLIP
  166.     
  167.     // Create the primary surface with 1 back buffer
  168.     ZeroMemory(&ddsd, sizeof(ddsd)) ;
  169.     ddsd.dwSize = sizeof(ddsd) ;
  170.     
  171. #ifndef NOFLIP
  172.     ddsd.dwFlags = DDSD_CAPS | DDSD_BACKBUFFERCOUNT ;
  173.     ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE |
  174.         DDSCAPS_FLIP | 
  175.         DDSCAPS_COMPLEX ;
  176.     ddsd.dwBackBufferCount = 1 ;
  177. #else
  178.     ddsd.dwFlags = DDSD_CAPS ;
  179.     ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE ;
  180. #endif  // NOFLIP
  181.     
  182.     hr = m_pDDObject->CreateSurface(&ddsd, &m_pPrimary, NULL) ;
  183.     if (FAILED(hr))
  184.     {
  185. #ifndef NOFLIP
  186.         MessageBox(hWndApp, TEXT("CreateSurface(Primary, flip(1), complex) failed"), 
  187.             TEXT("Error"), MB_OK | MB_ICONSTOP) ;
  188. #else
  189.         MessageBox(hWndApp, TEXT("CreateSurface(Primary, noflip, no backbuffer) failed"), 
  190.             TEXT("Error"), MB_OK | MB_ICONSTOP) ;
  191. #endif // NOFLIP
  192.         return hr ;
  193.     }
  194.     
  195. #ifndef NOFLIP
  196.     // Get a pointer to the back buffer
  197.     ddscaps.dwCaps = DDSCAPS_BACKBUFFER ;
  198.     hr = m_pPrimary->GetAttachedSurface(&ddscaps, &m_pBackBuff) ;
  199.     if (FAILED(hr))
  200.     {
  201.         MessageBox(hWndApp, TEXT("GetAttachedSurface() failed to get back buffer"),
  202.             TEXT("Error"), MB_OK | MB_ICONSTOP) ;
  203.         return hr ;
  204.     }
  205. #endif // NOFLIP
  206.     
  207.     // Get the screen size and save it as a rect
  208.     ZeroMemory(&ddsd, sizeof(ddsd)) ;
  209.     ddsd.dwSize = sizeof(ddsd) ;
  210.     hr = m_pPrimary->GetSurfaceDesc(&ddsd) ;
  211.     if (! (SUCCEEDED(hr) && (ddsd.dwFlags & DDSD_WIDTH) && (ddsd.dwFlags & DDSD_HEIGHT)) )
  212.     {
  213.         MessageBox(hWndApp, TEXT("GetSurfaceDesc() failed to get surface width & height"),
  214.             TEXT("Error"), MB_OK | MB_ICONSTOP) ;
  215.         return hr ;
  216.     }
  217.     
  218.     SetRect(&m_RectScrn, 0, 0, ddsd.dwWidth, ddsd.dwHeight) ;
  219.     
  220.     // Reset some buffer drawing flags, values etc.
  221.     m_iCount = 0 ;
  222.     m_bFrontBuff = TRUE ;
  223.     m_bInExclMode = TRUE ;
  224.     
  225.     return S_OK ;
  226. }
  227.  
  228.  
  229. //
  230. // CDDrawObject::StopExclusiveMode(): Releases primary buffer, exits 
  231. // exclusive mode, resets some variables/flags.
  232. //
  233. HRESULT CDDrawObject::StopExclusiveMode(HWND hWndApp)
  234. {
  235.     DbgLog((LOG_TRACE, 5, TEXT("CDDrawObject::StopExclusiveMode() entered"))) ;
  236.     
  237.     HRESULT hr ;
  238.     
  239.     if (m_pBackBuff)
  240.     {
  241.         hr = m_pBackBuff->Release() ;  // release back buffer
  242.         m_pBackBuff = NULL ;  // no back buffer anymore
  243.     }
  244.  
  245. #ifndef NOFLIP
  246.     if (m_pDDObject)
  247.     {
  248.         // Restore display to previous mode (set with SetDisplayMode())
  249.         hr = m_pDDObject->RestoreDisplayMode();
  250.         if (FAILED(hr))
  251.         {
  252.             DbgLog((LOG_ERROR, 0, TEXT("ERROR: RestoreDisplayMode failed (Error 0x%lx)"), hr)) ;
  253.             MessageBox(hWndApp, TEXT("RestoreDisplayMode failed"), 
  254.                 TEXT("Error"), MB_OK | MB_ICONSTOP) ;
  255.         }
  256.     }
  257. #endif // NOFLIP
  258.  
  259.     // Release the primary surface (and attached buffer with it)
  260.     if (m_pPrimary)
  261.     {
  262.         hr = m_pPrimary->Release() ;  // release primary surface
  263.         m_pPrimary = NULL ;
  264.     }
  265.     
  266.     // Get out of fullscreen exclusive mode
  267.     if (m_pDDObject)
  268.     {
  269.         hr = m_pDDObject->SetCooperativeLevel(hWndApp, DDSCL_NORMAL) ;
  270.         if (FAILED(hr))
  271.         {
  272.             MessageBox(hWndApp, 
  273.                 TEXT("SetCooperativeLevel() failed to go back to normal mode"), 
  274.                 TEXT("Error"), MB_OK | MB_ICONSTOP) ;
  275.             return hr ;
  276.         }
  277.  
  278.         m_pDDObject->Release() ;  // now release the DDraw object
  279.         m_pDDObject = NULL ;      // no more DDraw object
  280.     }
  281.     
  282.     // Reset the color key and screen, video rects.
  283.     m_dwVideoKeyColor = RGB(255, 0, 255) ;
  284.     SetRect(&m_RectScrn, 0, 0, 0, 0) ;
  285.     SetRect(&m_RectVideo, 0, 0, 0, 0) ;
  286.     
  287.     m_bInExclMode = FALSE ;
  288.     
  289.     return S_OK ;
  290. }
  291.  
  292.  
  293. //
  294. // CDDrawObject::DrawOnSurface(): Private method to draw stuff on back buffer
  295. //
  296. void CDDrawObject::DrawOnSurface(LPDIRECTDRAWSURFACE pSurface)
  297. {
  298.     DbgLog((LOG_TRACE, 5, TEXT("CDDrawObject::DrawOnSurface() entered"))) ;
  299.     
  300.     HDC     hDC ;
  301.     TCHAR   achBuffer[30] ;
  302.     
  303.     if (DD_OK == pSurface->GetDC(&hDC))
  304.     {
  305.         // write fonr/back to show buffer flipping
  306.         SetBkColor(hDC, RGB(0, 0, 255)) ;
  307.         SetTextColor(hDC, RGB(255, 255, 0)) ;
  308.         wsprintf(achBuffer, TEXT(" %-12s: %6.6d "), 
  309.                  m_bFrontBuff ? m_szFrontMsg : m_szBackMsg, m_iCount) ;
  310.         TextOut(hDC, 20, 10, achBuffer, lstrlen(achBuffer)) ;
  311.         
  312.         // Write the instructions
  313.         SetBkColor(hDC, RGB(0, 0, 0)) ;
  314.         SetTextColor(hDC, RGB(0, 255, 255)) ;
  315.         TextOut(hDC, m_RectScrn.left + 100, m_RectScrn.bottom - 20, m_szDirection, lstrlen(m_szDirection)) ;
  316.         
  317.         // Draw the ball on screen now
  318.         HBRUSH hBrush = (HBRUSH) SelectObject(hDC, m_hBrush) ; // select special brush
  319.         HPEN   hPen   = (HPEN) SelectObject(hDC, m_hPen) ;     // select special pen 
  320.         Ellipse(hDC, m_iBallCenterX - BALL_RADIUS, m_iBallCenterY - BALL_RADIUS, 
  321.             m_iBallCenterX + BALL_RADIUS, m_iBallCenterY + BALL_RADIUS) ;
  322.         SelectObject(hDC, hBrush) ;  // restore original brush
  323.         SelectObject(hDC, hPen) ;    // restore original pen
  324.         
  325.         pSurface->ReleaseDC(hDC) ;  // done now; let go of the DC
  326.     }
  327. }
  328.  
  329.  
  330. //
  331. // CDDrawObject::ConvertColorRefToPhysColor(): Converts a COLORREF to a
  332. // DWORD physical color value based on current display mode.
  333. //
  334. // NOTE: This method is useful ONLY if you want to get the COLORREF from
  335. // OverlayMixer (rather than the physical color as a DWORD) and convert
  336. // it yourself.  But OverlayMixer does it for you anyway; so the utility
  337. // of this method is quite minimal.
  338. //
  339. HRESULT CDDrawObject::ConvertColorRefToPhysColor(COLORREF rgb, DWORD *pdwPhysColor)
  340. {
  341.     HRESULT         hr ;
  342.     COLORREF        rgbCurr ;
  343.     HDC             hDC ;
  344.     DDSURFACEDESC   ddsd ;
  345.     
  346.     ASSERT(rgb != CLR_INVALID) ;
  347.     
  348.     //  use GDI SetPixel to color match for us
  349.     hr = m_pBackBuff->GetDC(&hDC) ;
  350.     if (DD_OK != hr)
  351.     {
  352.         DbgLog((LOG_ERROR, 0, TEXT("m_pBackBuff->GetDC() failed (Error 0x%lx)"), hr)) ;
  353.         return hr ;
  354.     }
  355.     rgbCurr = GetPixel(hDC, 0, 0) ;             // save current pixel value
  356.     SetPixel(hDC, 0, 0, rgb) ;               // set our value
  357.     m_pBackBuff->ReleaseDC(hDC) ;
  358.     
  359.     // now lock the surface so we can read back the converted color
  360.     ZeroMemory(&ddsd, sizeof(ddsd)) ;
  361.     ddsd.dwSize = sizeof(ddsd) ;
  362.     while (DDERR_WASSTILLDRAWING == (hr = m_pBackBuff->Lock(NULL, &ddsd, 0, NULL)))  // until unlocked...
  363.         ;               // ...just wait
  364.     
  365.     if (DD_OK == hr)
  366.     {
  367.         // get DWORD
  368.         *pdwPhysColor = *(DWORD *) ddsd.lpSurface ;
  369.         
  370.         // mask it to bpp
  371.         if (ddsd.ddpfPixelFormat.dwRGBBitCount < 32)
  372.             *pdwPhysColor &= (1 << ddsd.ddpfPixelFormat.dwRGBBitCount) - 1 ;
  373.         m_pBackBuff->Unlock(NULL) ;
  374.     }
  375.     else
  376.     {
  377.         DbgLog((LOG_ERROR, 0, TEXT("m_pBackBuff->Lock() failed (Error 0x%lx)"), hr)) ;
  378.         return hr ;
  379.     }
  380.     
  381.     //  now restote the pixel to the color that was there
  382.     hr = m_pBackBuff->GetDC(&hDC) ;
  383.     if (DD_OK != hr)
  384.     {
  385.         DbgLog((LOG_ERROR, 0, TEXT("m_pBackBuff->GetDC() failed (Error 0x%lx)"), hr)) ;
  386.         return hr ;
  387.     }
  388.     SetPixel(hDC, 0, 0, rgbCurr) ;
  389.     m_pBackBuff->ReleaseDC(hDC) ;
  390.     
  391.     return S_OK ;
  392. }
  393.  
  394.  
  395. #if 0
  396. //
  397. // CDDrawObject::SetColorKey(): Creates a DWORD physical color out COLORREF.
  398. // 
  399. // NOTE: This method is useful only if you want to do the conversion. We have
  400. // defined an inline version in ddrawobj.h file.
  401. //
  402. HRESULT CDDrawObject::SetColorKey(COLORKEY *pColorKey)
  403. {
  404.     if (NULL == pColorKey)
  405.         return E_INVALIDARG ;
  406.     
  407.     DWORD    dwPhysColor ;
  408.     HRESULT  hr = ConvertColorRefToPhysColor(pColorKey->LowColorValue, &dwPhysColor) ;
  409.     if (FAILED(hr))
  410.         return hr ;
  411.     
  412.     m_dwVideoKeyColor = dwPhysColor ;
  413.     return S_OK ;
  414. }
  415. #endif // #if 0
  416.  
  417.  
  418. //
  419. // CDDrawObject::FillSurface(): Private method to fill the back buffer with black
  420. // color and put the color key in teh video area.
  421. //
  422. // NOTE: Re-filling the back buffer every time is required ONLY IF the video 
  423. // position keeps changing. Otherwise setting it once should be fine.
  424. // 
  425. HRESULT CDDrawObject::FillSurface(IDirectDrawSurface *pDDSurface)
  426. {
  427.     DbgLog((LOG_TRACE, 5, TEXT("CDDrawObject::FillSurface() entered"))) ;
  428.  
  429.     if (NULL == pDDSurface)
  430.         return E_INVALIDARG ;
  431.     
  432.     // Repaint the whole specified surface
  433.     HRESULT  hr ;
  434.     DDBLTFX  ddFX ;
  435.     ZeroMemory(&ddFX, sizeof(ddFX)) ;
  436.     ddFX.dwSize = sizeof(ddFX) ;
  437.     ddFX.dwFillColor = m_dwScrnColor ;
  438.     
  439.     hr = pDDSurface->Blt(&m_RectScrn, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &ddFX) ;
  440.     if (FAILED(hr))
  441.     {
  442.         DbgLog((LOG_ERROR, 0, TEXT("pDDSurface->Blt for screen failed (Error 0x%lx)"), hr)) ;
  443.         DbgLog((LOG_ERROR, 0, TEXT("Destination Rect: (%ld, %ld, %ld, %ld), Color = 0x%lx"), 
  444.             m_RectScrn.left, m_RectScrn.top, m_RectScrn.right, m_RectScrn.bottom, m_dwScrnColor)) ;
  445.         return hr ;
  446.     }
  447.     
  448.     // Draw color key on the video area of given surface, ONLY IF we are supposed
  449.     // to paint color key in the video area.
  450.     if (m_bOverlayVisible)
  451.     {
  452.         ddFX.dwFillColor = m_dwVideoKeyColor ;
  453.         hr = pDDSurface->Blt(&m_RectVideo, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &ddFX) ;
  454.         if (FAILED(hr))
  455.         {
  456.             DbgLog((LOG_ERROR, 0, TEXT("pDDSurface->Blt for video failed (Error 0x%lx)"), hr)) ;
  457.             DbgLog((LOG_ERROR, 0, TEXT("Destination Rect: (%ld, %ld, %ld, %ld), Color = 0x%lx"), 
  458.                 m_RectVideo.left, m_RectVideo.top, m_RectVideo.right, m_RectVideo.bottom, 
  459.                 m_dwVideoKeyColor)) ;
  460.             return hr ;
  461.         }
  462.     }
  463.     else
  464.         DbgLog((LOG_TRACE, 5, TEXT("Color keying of video area skipped"))) ;
  465.     
  466.     return S_OK ;
  467. }
  468.  
  469.  
  470. //
  471. // CDDrawObject::UpdateAndFlipSurfaces(): Prepares the back buffer and flips.
  472. //
  473. HRESULT CDDrawObject::UpdateAndFlipSurfaces(void)
  474. {
  475.     DbgLog((LOG_TRACE, 5, TEXT("CDDrawObject::UpdateAndFlipSurfaces() entered"))) ;
  476.     
  477.     // Draw screen and color key on the current back buffer
  478.     HRESULT  hr = FillSurface(m_pBackBuff) ;
  479.     if (FAILED(hr))
  480.     {
  481.         DbgLog((LOG_ERROR, 1, TEXT("UpdateAndFlipSurfaces() skipped as FillSurface() failed"), hr)) ;
  482.         return hr ;   // or return S_OK??
  483.     }
  484.     
  485.     IncCount() ;                    // increment flip count first
  486.     m_bFrontBuff = !m_bFrontBuff ;  // toggle flag
  487.     DrawOnSurface(m_pBackBuff) ;  // draw next text on the back buffer
  488.     
  489.     // Keep trying to flip the buffers until successful
  490.     while (1)
  491.     {
  492.         hr = m_pPrimary->Flip(NULL, 0) ;  // flip the surfaces
  493.         if (DD_OK == hr)  // success!!
  494.         {
  495.             break ;
  496.         }
  497.         if (DDERR_SURFACELOST == hr)   // surface lost; try to restore
  498.         {
  499.             DbgLog((LOG_TRACE, 5, TEXT("DirectDraw surface was lost. Trying to restore..."))) ;
  500.             hr = m_pPrimary->Restore() ;
  501.             if (DD_OK != hr)  // couldn't restore surface
  502.             {
  503.                 DbgLog((LOG_ERROR, 0, TEXT("IDirectDrawSurface::Restore() failed (Error 0x%lx)"), hr)) ;
  504.                 break ;
  505.             }
  506.         }
  507.         if (DDERR_WASSTILLDRAWING != hr)  // some weird error -- bail out
  508.         {
  509.             DbgLog((LOG_ERROR, 0, TEXT("IDirectDrawSurface::Flip() failed (Error 0x%lx)"), hr)) ;
  510.             break ;
  511.         }
  512.     }
  513.     
  514.     return hr ;
  515. }
  516.  
  517.  
  518. //
  519. // CDDrawObject::SetVideoPosition(): Receives the video position in terms of screen
  520. // coordinates.
  521. //
  522. void CDDrawObject::SetVideoPosition(DWORD dwVideoLeft, DWORD dwVideoTop, 
  523.                                     DWORD dwVideoWidth, DWORD dwVideoHeight)
  524. {
  525.     DbgLog((LOG_TRACE, 5, TEXT("CDDrawObject::SetVideoPosition() entered"))) ;
  526.     
  527.     SetRect(&m_RectVideo, dwVideoLeft, dwVideoTop, dwVideoLeft + dwVideoWidth,
  528.         dwVideoTop + dwVideoHeight) ;
  529. }
  530.  
  531.  
  532. //
  533. // CDDrawObject::SetBallPosition(): Uses the video position to initialize the ball's
  534. // position to the center of the video.
  535. //
  536. void CDDrawObject::SetBallPosition(DWORD dwVideoLeft, DWORD dwVideoTop, 
  537.                                    DWORD dwVideoWidth, DWORD dwVideoHeight)
  538. {
  539.     DbgLog((LOG_TRACE, 5, TEXT("CDDrawObject::SetBallPosition() entered"))) ;
  540.     
  541.     // Place the ball at the middle of video on start
  542.     m_iBallCenterX = dwVideoLeft + dwVideoWidth  / 2 ;
  543.     m_iBallCenterY = dwVideoTop  + dwVideoHeight / 2 ;
  544. }
  545.  
  546.  
  547. //
  548. // CDDrawObject::MoveBallPosition(): Moves the ball L/R/U/D and keeps it within
  549. // the video area..
  550. //
  551. void CDDrawObject::MoveBallPosition(int iDirX, int iDirY)
  552. {
  553.     DbgLog((LOG_TRACE, 5, TEXT("CDDrawObject::MoveBallPosition(%d, %d) entered"),
  554.         iDirX, iDirY)) ;
  555.     
  556.     m_iBallCenterX += iDirX ;
  557.     m_iBallCenterY += iDirY ;
  558.     
  559.     // Keep the ball inside the video rect
  560.     if (m_iBallCenterX < m_RectVideo.left + BALL_RADIUS)
  561.         m_iBallCenterX = m_RectVideo.left + BALL_RADIUS ;
  562.     else if (m_iBallCenterX > m_RectVideo.right - BALL_RADIUS)
  563.         m_iBallCenterX = m_RectVideo.right - BALL_RADIUS ;
  564.     
  565.     if (m_iBallCenterY < m_RectVideo.top + BALL_RADIUS)
  566.         m_iBallCenterY = m_RectVideo.top + BALL_RADIUS ;
  567.     else if (m_iBallCenterY > m_RectVideo.bottom - BALL_RADIUS)
  568.         m_iBallCenterY = m_RectVideo.bottom - BALL_RADIUS ;
  569. }
  570.  
  571.  
  572.  
  573. //
  574. // Overlay Callback object implementation
  575. //
  576. COverlayCallback::COverlayCallback(CDDrawObject *pDDrawObj, HWND hWndApp, HRESULT *phr) :
  577. CUnknown("Overlay Callback Object", NULL, phr),
  578. m_pDDrawObj(pDDrawObj),
  579. m_hWndApp(hWndApp)
  580. {
  581.     DbgLog((LOG_TRACE, 5, TEXT("COverlayCallback::COverlayCallback() entered"))) ;
  582.     ASSERT(m_pDDrawObj) ;
  583.     AddRef() ;    // increment ref count for itself
  584. }
  585.  
  586.  
  587. COverlayCallback::~COverlayCallback()
  588. {
  589.     DbgLog((LOG_TRACE, 5, TEXT("COverlayCallback::~COverlayCallback() entered"))) ;
  590. }
  591.  
  592.  
  593. HRESULT COverlayCallback::OnUpdateOverlay(BOOL  bBefore,
  594.                                           DWORD dwFlags,
  595.                                           BOOL  bOldVisible,
  596.                                           const RECT *prcSrcOld,
  597.                                           const RECT *prcDestOld,
  598.                                           BOOL  bNewVisible,
  599.                                           const RECT *prcSrcNew,
  600.                                           const RECT *prcDestNew)
  601. {
  602.     DbgLog((LOG_TRACE, 5, TEXT("COverlayCallback::OnUpdateOverlay(%s, ...) entered"),
  603.             bBefore ? "TRUE" : "FALSE")) ;
  604.  
  605.     if (NULL == m_pDDrawObj)
  606.     {
  607.         DbgLog((LOG_ERROR, 1, TEXT("ERROR: NULL DDraw object pointer was specified"))) ;
  608.         return E_POINTER ;
  609.     }
  610.  
  611.     if (bBefore)  // overlay is going to be updated
  612.     {
  613.         DbgLog((LOG_TRACE, 5, TEXT("Just turn off color keying and return"))) ;
  614.         m_pDDrawObj->SetOverlayState(FALSE) ;   // don't paint color key in video's position
  615. #ifndef NOFLIP
  616.         m_pDDrawObj->UpdateAndFlipSurfaces() ;  // flip the surface so that video doesn't show anymore
  617. #endif // NOFLIP
  618.         return S_OK ;
  619.     }
  620.  
  621.     //
  622.     // After overlay has been updated. Turn on/off overlay color keying based on 
  623.     // flags and use new source/dest position etc.
  624.     //
  625.     if (dwFlags & (AM_OVERLAY_NOTIFY_VISIBLE_CHANGE |
  626.                    AM_OVERLAY_NOTIFY_SOURCE_CHANGE  |
  627.                    AM_OVERLAY_NOTIFY_DEST_CHANGE))   // it's a valid flag
  628.         m_pDDrawObj->SetOverlayState(bNewVisible) ;  // paint/don't paint color key based on param
  629.  
  630.     if (dwFlags & AM_OVERLAY_NOTIFY_VISIBLE_CHANGE)  // overlay visibility state change
  631.     {
  632.         DbgLog((LOG_TRACE, 5, TEXT(".._NOTIFY_VISIBLE_CHANGE from %s to %s"), 
  633.                 bOldVisible ? "TRUE" : "FALSE", bNewVisible ? "TRUE" : "FALSE")) ;
  634.     }
  635.  
  636.     if (dwFlags & AM_OVERLAY_NOTIFY_SOURCE_CHANGE)   // overlay source rect change
  637.     {
  638.         DbgLog((LOG_TRACE, 5, TEXT(".._NOTIFY_SOURCE_CHANGE from (%ld, %ld, %ld, %ld) to (%ld, %ld, %ld, %ld)"), 
  639.                 prcSrcOld->left, prcSrcOld->top, prcSrcOld->right, prcSrcOld->bottom,
  640.                 prcSrcNew->left, prcSrcNew->top, prcSrcNew->right, prcSrcNew->bottom)) ;
  641.     }
  642.  
  643.     if (dwFlags & AM_OVERLAY_NOTIFY_DEST_CHANGE)     // overlay destination rect change
  644.     {
  645.         DbgLog((LOG_TRACE, 5, TEXT(".._NOTIFY_DEST_CHANGE from (%ld, %ld, %ld, %ld) to (%ld, %ld, %ld, %ld)"), 
  646.                 prcDestOld->left, prcDestOld->top, prcDestOld->right, prcDestOld->bottom,
  647.                 prcDestNew->left, prcDestNew->top, prcDestNew->right, prcDestNew->bottom)) ;
  648.         m_pDDrawObj->SetVideoPosition(prcDestNew->left, prcDestNew->top, 
  649.                                       RECTWIDTH(*prcDestNew), RECTHEIGHT(*prcDestNew)) ;
  650.     }
  651.  
  652.     return S_OK ;
  653. }
  654.  
  655.  
  656. HRESULT COverlayCallback::OnUpdateColorKey(COLORKEY const *pKey,
  657.                                            DWORD           dwColor)
  658. {
  659.     DbgLog((LOG_TRACE, 5, TEXT("COverlayCallback::OnUpdateColorKey(.., 0x%lx) entered"), dwColor)) ;
  660.  
  661.     return S_OK ;
  662. }
  663.  
  664.  
  665. HRESULT COverlayCallback::OnUpdateSize(DWORD dwWidth, DWORD dwHeight, 
  666.                                        DWORD dwARWidth, DWORD dwARHeight)
  667. {
  668.     DbgLog((LOG_TRACE, 5, TEXT("COverlayCallback::OnUpdateSize(%lu, %lu, %lu, %lu) entered"), 
  669.             dwWidth, dwHeight, dwARWidth, dwARHeight)) ;
  670.  
  671.     PostMessage(m_hWndApp, WM_SIZE_CHANGE, 0, 0) ;
  672.  
  673.     return S_OK ;
  674. }
  675.